/*
 * @Author: Wangjun
 * @Date: 2023-03-23 15:50:31
 * @LastEditTime: 2023-05-06 15:24:03
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \real2ckd:\go\src\gitee.com\haodreams\libs\itemx\rows.go
 * hnxr
 */
package itemx

import (
	"fmt"
	"strings"
)

// 一个测点的完整信息
type Rows struct {
	offset    int //起始偏移
	pos       int //当前位置
	tsName    string
	Desc      string         //描述
	mapFiled  map[string]int //简码
	Columns   []string
	insertSQL string //insert sql  语句
	createSQL string
	vals      [][]any
	array     []*Row
}

/**
 * @description:
 * @param {int} size 最大缓存数量 一天是86400
 * @param {*} tableName 写入的表名
 * @param {string} tsName 时间戳名称 ，默认是ts
 * @param {[]string} fileds //列名
 * @return {*}
 */
func NewRows(tableName string, fileds []string, tsName ...string) *Rows {
	m := new(Rows)
	m.offset = 2 //id + creat_time 的个数
	if len(tsName) > 0 && tsName[0] != "" {
		m.tsName = tsName[0]
	} else {
		m.tsName = "ts"
	}

	m.Columns = fileds
	const size = 50000

	wh := strings.Repeat("?,", len(fileds)+m.offset)
	wh = wh[:len(wh)-1]
	cols := strings.Join(fileds, ",")
	cols = strings.ToLower(cols)
	m.insertSQL = fmt.Sprintf("INSERT INTO hnxr.%s (%s, id, %s) VALUES (%s);", tableName, m.tsName, cols, wh)

	cols = strings.ReplaceAll(cols, ",", " Decimal(18,2),")
	cols += " Decimal(18,2)"
	m.createSQL = fmt.Sprintf("CREATE TABLE IF NOT EXISTS hnxr.%s (%s DateTime, id Int32, write_time DateTime DEFAULT now(), %s) ENGINE = ReplacingMergeTree PARTITION BY toYYYYMMDD(%s) PRIMARY KEY (%s, id) ORDER BY (%s, id) TTL %s + toIntervalMonth(24) SETTINGS index_granularity = 8192",
		tableName, m.tsName, cols, m.tsName, m.tsName, m.tsName, m.tsName)
	m.mapFiled = map[string]int{}
	for i, filed := range fileds {
		m.mapFiled[filed] = i
	}

	m.vals = make([][]any, size)
	m.array = make([]*Row, size)
	for i := range m.array {
		m.array[i] = NewRow(m.offset, len(fileds))
	}
	return m
}

// ck 插入的sql
func (m *Rows) InsertSQL() string {
	return m.insertSQL
}

// ck 建表的sql
func (m *Rows) CreateSQL() string {
	return m.createSQL
}

/**
 * @description: 获取指定列名的索引
 * @param {string} name
 * @return {*}
 */
func (m *Rows) GetIndex(name string) int {
	idx, ok := m.mapFiled[name]
	if ok {
		return idx
	}
	return -1
}

/**
 * @description: 获取指定的行
 * @param {int} idx 行号
 * @return {*}
 */
func (m *Rows) GetRow() *Row {
	if m.pos < len(m.array) {
		row := m.array[m.pos]
		m.pos++
		return row
	}
	return nil
}

/**
 * @description: 获取数据的大小
 * @return {*}
 */
func (m *Rows) Size() int {
	return m.pos
}

/**
 * @description: 转化符合条件的数组
 * @return {*}
 */
func (m *Rows) ToArray() [][]any {
	idx := 0
	for i := 0; i < m.pos; i++ {
		item := m.array[i]
		if item.ok {
			m.vals[idx] = item.Vals
			idx++
		}
	}
	return m.vals[:idx]
}

/**
 * @description: 代码复用， 出现新的测点
 * @return {*}
 */
func (m *Rows) Reset() {
	i := 0
	for ; i < m.pos; i++ {
		item := m.array[i]
		item.Reset()
	}
	m.pos = 0
}

// Row 对应数据的行
type Row struct {
	ok   bool
	vals []float64
	Vals []any
}

// 行的复用，数据初始化
func (m *Row) Reset() {
	m.ok = false
	n := len(m.vals)
	for i := 0; i < n; i++ {
		m.vals[i] = -9999
	}
}

/**
 * @description: 设置时间戳
 * @param {int64} ts
 * @return {*}
 */
func (m *Row) SetTimestamp(ts int64) *Row {
	m.Vals[0] = ts
	return m
}

/**
 * @description: 设置ID的值
 * @param {int} id
 * @return {*}
 */
func (m *Row) SetID(id int) *Row {
	m.Vals[1] = id
	return m
}

// 对指定的列赋值
func (m *Row) SetValue(idx int, v float64) {
	m.vals[idx] = v
	m.ok = true
}

// 新建一行
func NewRow(pos, n int) *Row {
	m := new(Row)
	m.vals = make([]float64, n)
	n += pos
	m.Vals = make([]any, n)
	for i := pos; i < n; i++ {
		idx := i - pos
		m.vals[idx] = -9999 //数据初始化
		m.Vals[i] = &m.vals[idx]
	}
	return m
}
